package com.hibegin.http.server.util;


import com.szwistar.common.datastruct.Utils;
import com.szwistar.common.os.FileUtils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

public class MimeTypeUtil {
    private static final Logger LOG = LoggerFactory.getLogger(MimeTypeUtil.class);

    // 文件扩展名 -> MimeType 类型映射表
    // key: 文件扩展名
    // value: MimeType 类型字符串
    private static Map<String, String> mimeMap = new HashMap<String, String>();

    // MimeType 类型是否值得压缩映射表
    // key: MimeType 类型字符串
    // value: 是否值得压缩
    private static Map<String, Boolean> compressibleMap = new HashMap<String, Boolean>();

    // MimeType 类型的默认字符编码(如果有的话)
    // key: MimeType 类型字符串
    // charset: 默认字符编码
    private static Map<String, String> charsetMap = new HashMap<String, String>();

    /**
     * 从属性对象中加载
     */
    public static boolean loadMimeType(Properties prop) {
        if(Utils.isEmpty(prop)) { return false; }
        for(Object key: prop.keySet()) {
        	String value = prop.get(key).toString();
        	// 分隔字符串，如：text/plain,flat,utf-8
        	String[] values = value.split(",");
        	if(values == null) { continue; }
        	// 保存 文件扩展名 -> MIME 类型表
        	if(values.length > 0) { mimeMap.put(key.toString(), values[0]); }
        	// 是否值得压缩
        	if(values.length > 1 && "flat".equalsIgnoreCase(values[1])) { compressibleMap.put(values[0], Boolean.TRUE); }
        	// 默认字符编码指示
        	if(values.length > 2) { charsetMap.put(values[0], values[2]); }
        }
        return true;
    }

    /**
     * 从输入流中加载，并关闭流
     */
    public static boolean loadMimeType(InputStream ins) {
        try {
            Properties prop = new Properties();
            prop.load(ins);
            return loadMimeType(prop);
        } catch (Exception e) {
            LOG.error("", e);
            return false;
        } finally {
        	// 关闭流
        	FileUtils.close(ins);
        }
    }

    /**
     * 从文件加载
     */
    public static boolean loadMimeType(File file) {
    	LOG.debug("加载 MineType 配置文件 {} ...", file);
        try {
            return loadMimeType(new FileInputStream(file));
        } catch (Exception e) {
            LOG.error("", e);
            return false;
        }
    }

    /**
     * 根据文件名获取对应的 MIME 类型 + 编码
     */
    public static String getContentType(String ext) {
        String type = mimeMap.get(ext);
        if (type == null) {
            return "application/octet-stream";
        }
        String charset = charsetMap.get(type);
        if(charset != null) { type = type + ";charset=" + charset; }
        return type;
    }

    /**
     * Content-Type 是否值得压缩？
     */
    public static boolean compressible(String contentType) {
    	// 防止 Content-Type 中有其它信息
    	String[] parts = contentType.split(";");
    	Boolean ret = compressibleMap.get(parts[0]);
		return (ret == null) ? false : ret;
    }

    /**
     * 文件扩展名对应的 MimeType 是否值得压缩？
     */
    public static boolean compressibleExt(String ext) {
		return compressibleMap.get(mimeMap.get(ext));
    }

    /**
     * 获取 Content-Type 的字符编码
     * @param contentType Content-Type 字符串，其中可以指定编码，如： "text/plain;charset=utf-8"
     * @return 字符编码
     * 	<li>如果 Content-Type 字符串中指定了编码，则使用指定的编码
     *	<li>如果 Content-Type 字符串中未指定编码，则使用 MIME 类型配置的默认编码(可能为 null)
     */
    public static String getCharset(String contentType) {
    	// 查找 Content-Type 字符串中指定的编码
		String[] parts = contentType.split(";charset=");
		if(parts != null && parts.length > 1) { return parts[1]; }

		// 使用 MIME 类型配置的默认编码
		return charsetMap.get(parts[0]);
    }

    /**
     * 文件扩展名对应的 MimeType 默认字符编码
     */
    public static String getCharsetExt(String ext) {
		return charsetMap.get(mimeMap.get(ext));
    }

    /**
     * 内容是否是文本型的
     */
    public static boolean isText(String contentType) {
    	if(contentType == null) { return false; }
    	return  contentType.startsWith("text/") ||
    			contentType.startsWith("application/json") ||
    			contentType.startsWith("application/xml") ||
    			contentType.startsWith("application/xhtml+xml") ||
    			contentType.startsWith("svg=image/svg+xml") ||
    			contentType.startsWith("application/ecmascript") ||
    			contentType.startsWith("application/javascript") ||
    			contentType.startsWith("application/typescript") ||
    			contentType.startsWith("application/x-csh");
    }
}
